#include "mini.kit/config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include "mini.kit/text.h"

namespace MINIKIT
{

Config::Config()
{
}

Config::Config(const std::string& filepath)
{
	this->filepath = filepath;
}

Config::~Config()
{
}

void Config::setItem( 
	const std::string& sec, 
	const std::string& key, 
	const std::string& val
)
{
	this->section_map[sec][key] = val;
}

const std::string& Config::getItem( 
	const std::string& sec, 
	const std::string& key, 
	const std::string& defval
)
{
	std::map<std::string, SectionConfig>::iterator itr = this->section_map.find(sec);	
	if( itr==this->section_map.end() )
		return defval;
	SectionConfig::iterator itr_kv = itr->second.find(key);
	if( itr_kv==itr->second.end() )
		return defval;
	return itr_kv->second;
}


int32_t Config::getInt32(
	const std::string& sec, 
	const std::string& key, 
	int32_t            defval
)
{
	char buf[20] = {0};
	::snprintf( buf, sizeof(buf), "%d", defval);
	const std::string& s = this->getItem( sec, key, buf );
	if( s.empty() ) 
		return 0;
	else
		(int32_t)::strtoull( s.c_str(), NULL, 10 );
}

int64_t Config::getInt64(
	const std::string& sec, 
	const std::string& key, 
	int64_t            defval
)
{
	char buf[40] = {0};
	::snprintf( buf, sizeof(buf), "%llu", defval);
	const std::string& s = this->getItem( sec, key, buf );
	if( s.empty() ) 
		return 0;
	else
		(int64_t)::strtoull( s.c_str(), NULL, 10 );
}

const std::string& Config::getStr(
	const std::string& sec, 
	const std::string& key, 
	const std::string& defval
)
{
	return this->getItem( sec, key, defval );
}

void    Config::setFile( const std::string& filepath )
{
	this->filepath = filepath;
}

int32_t Config::reload() throw(std::exception)
{
#define MAX_LINE_LEN  10240
	std::fstream fs;
	fs.open( this->filepath.c_str(), std::fstream::in );
	
	char   buf[MAX_LINE_LEN] = {0};
	size_t len = 0;
	std::string section="";
	int8_t got_section = 0;
	SectionConfig key_value;
	while(!fs.eof()&&fs.good())
	{
		::memset( buf, 0x00, sizeof(buf) );
		fs.getline( buf, sizeof(buf) );
		len = ::strlen(buf);
		if( len==0 )
			continue;

		if( buf[len-1]=='\r' )
			buf[len-1] = '\0';

		std::string line(buf);
		if( line.empty() )
		{
			::memset( buf, 0x00, sizeof(buf) );
			continue;
		}

		Text::trim(line);
		size_t pos = line.find_first_of("[");
		if(pos != std::string::npos) {  // section define .
			size_t endpos = line.find_last_of("]");
			if( endpos != std::string::npos ) 
			{  
				if( got_section == 1 ) {
					section_map[section] = key_value;
				}
				// get new section.
				section = line.substr(pos+1,endpos-pos-1);
				got_section = 1;
				key_value.clear();
				::memset( buf, 0x00, sizeof(buf) );
				continue;
			}
			else 
			{
				return -1;
			}
		}
		ssize_t compos1 = line.find_first_of(";");
		ssize_t compos2 = line.find_first_of("#");
		if((compos1 != 0)&& (compos2!=0)) {
			size_t keypos = line.find_first_of("=");
			if(keypos!=std::string::npos) {
				std::string key = line.substr(0,keypos);
				std::string value = line.substr(keypos+1);
				Text::trim(key);
				Text::trim(value);
				key_value[key] = value;		 
			}
		}
	}
	if(!section.empty())
		section_map[section] = key_value;
	fs.close();
	return 0;
#undef MAX_LINE_LEN
}


void    Config::output(std::ostream &s)
{
	std::map<std::string, SectionConfig>::const_iterator itr = this->section_map.begin();
	for( ; itr!=this->section_map.end(); itr++ )
	{
		s<<"["<<itr->first<<"]"<<std::endl;
		SectionConfig::const_iterator itr_kv = itr->second.begin();
		for( ; itr_kv!=itr->second.end(); itr_kv++ )
		{
			s<<itr_kv->first<<"="<<itr_kv->second<<std::endl;
		}
	}
}


};//namespace MINIKIT

